package com.hwy.chart.component

import android.graphics.*
import androidx.annotation.ColorInt
import com.hwy.chart.BaseChartView

/**
 * =======================================
 * 作者: hewenyu
 * 日期: 2022/5/11 0:06
 * 说明: 折线图组件
 * =======================================
 */
open class LineChartComponent<T>(chartView: BaseChartView) :
    BaseComponent<T>(chartView) where T : Comparable<T>, T : Number {

    protected val linePaint by lazy {
        Paint().apply {
            isAntiAlias = true
            isDither = true
            style = Paint.Style.STROKE
        }
    }

    /**
     * 线条路径
     */
    protected val linePath by lazy {
        Path()
    }

    /**
     * 线条颜色
     */
    @ColorInt
    var lineColor = Color.RED

    /**
     * 线条粗细
     */
    var lineWidth = 4F

    protected var shaderGradient: LinearGradient? = null

    /**
     * 记录折线的最后一个坐标
     */
    protected val lastPointF by lazy {
        PointF()
    }

    protected val shaderPaint by lazy {
        Paint().apply {
            isAntiAlias = true
            isDither = true
            style = Paint.Style.FILL_AND_STROKE
        }
    }

    /**
     * 阴影的路径
     */
    protected val shaderPath by lazy {
        Path()
    }

    /**
     * 是否绘制阴影
     */
    var isDrawShadow = false
        set(value) {
            if (field == value) {
                return
            }
            field = value
            chartView.invalidate()
        }

    protected val shaderMatrix by lazy {
        Matrix()
    }

    fun setGradient(@ColorInt startColor: Int, @ColorInt endColor: Int) {
        shaderGradient =
            LinearGradient(0F, 0F, 0F, 1F, startColor, endColor, Shader.TileMode.CLAMP)
    }

    override fun drawComponent(canvas: Canvas, bounds: RectF) {
        if (isDataChange()) {
            dataOffset = calculateLinePath(linePath, dataList, bounds)
        }
        updateAxisDataOffset(dataOffset)
        if (dataOffset > 0) {
            // 只有当path点的数量>0时，才需要绘制阴影
            drawShadow(canvas, bounds)
        }
        linePaint.run {
            color = lineColor
            strokeWidth = lineWidth
        }
        // 绘制曲线
        drawLinePath(canvas, linePath, linePaint)
    }

    /**
     * 绘制曲线
     */
    protected open fun drawLinePath(canvas: Canvas, path: Path, paint: Paint) {
        canvas.drawPath(path, paint)
    }

    /**
     * 计算需要绘制的path
     *
     * @return 返回当前path绘制的点的数量
     */
    protected open fun calculateLinePath(path: Path, list: ArrayList<T?>, bounds: RectF): Int {
        path.reset()
        lastPointF.set(0F, 0F)
        var count = 0
        list.forEachIndexed { index, entity ->
            entity?.run {
                val xCoordinate = calculateXCoordinate(index, bounds)
                val yCoordinate = calculateYCoordinate(index, this, bounds)
                yCoordinate?.let {
                    if (path.isEmpty) {
                        path.moveTo(xCoordinate, it)
                    } else {
                        path.lineTo(xCoordinate, it)
                    }
                    lastPointF.set(xCoordinate, it)
                    count++
                }
            }
        }
        return count
    }

    /**
     * 绘制线条阴影效果
     */
    protected open fun drawShadow(canvas: Canvas, bounds: RectF) {
        if (!isDrawShadow) {
            return
        }
        shaderGradient?.run {
            shaderMatrix.setScale(1F, bounds.height())
            setLocalMatrix(shaderMatrix)
            shaderPaint.shader = this
            shaderPath.reset()
            shaderPath.set(linePath)
            shaderPath.lineTo(lastPointF.x, bounds.bottom)
            shaderPath.lineTo(bounds.left, bounds.bottom)
            canvas.drawPath(shaderPath, shaderPaint)
        }
    }

}